iT邦幫忙

2026 iThome 鐵人賽

DAY 29
0
自我挑戰組

Laravel 讀碼源系列 第 29

美髮預約系統_customers 起手式

  • 分享至 

  • xImage
  •  

這裡要來介紹
https://laihao.vaserver.com/hairdressing
https://ithelp.ithome.com.tw/upload/images/20260907/20119035svoEPoGSZQ.png

裡面的顧客管理
就是customers得部分
https://laihao.vaserver.com/customers

https://ithelp.ithome.com.tw/upload/images/20260907/20119035opSO5vV40Z.png
這裡先來講解一下美髮系統跟美容系統的routes
美容系統
https://laihao.vaserver.com/spa-intro
就是/home/laihao/public_html/routes/web.php裡的
這段程式碼是 Laravel 的 routes/web.php 檔案,定義了整個網站的 URL 路由規則。你特別標記的這一段,是「美髮預約系統」與「SPA 美容系統」的核心路由。

以下我將這段程式碼分成幾個邏輯區塊,逐行解釋:

美髮預約系統(Hairdressing System)

// 預約管理(美髮預約系統)
Route::resource('appointments', 'AppointmentController')->except(['show']);
  • 建立一組 RESTful 路由,URL 前綴為 appointments,由 AppointmentController 處理。
  • except(['show']) 表示不產生 GET /appointments/{id} 這個「單一預約詳情」的路由。
  • 會自動產生:index, create, store, edit, update, destroy 等路由。
// 顧客管理(美髮預約系統)
Route::resource('customers', 'CustomerController')->except(['show']);
  • 同上,針對顧客資料的 CRUD 路由,不顯示單一顧客詳情頁面。
// 設計師管理(美髮預約系統)
Route::resource('staff', 'StaffController')->except(['show']);
  • 針對設計師(staff)資料的 CRUD 路由。
// 服務管理(美髮預約系統)
Route::resource('services', 'ServiceController')->except(['show']);
  • 針對美髮服務項目(如剪髮、染髮等)的 CRUD 路由。
// 商品管理(美髮預約系統)
Route::resource('hairdressingproducts', 'HairdressingProductController')
    ->except(['show'])
    ->parameters(['hairdressingproducts' => 'product']);
  • 針對美髮商品的 CRUD 路由。
  • parameters(['hairdressingproducts' => 'product']) 這行很重要:它把 URL 中的參數名稱從 hairdressingproducts 改成 product
    • 原本:/hairdressingproducts/{hairdressingproduct}/edit
    • 修改後:/hairdressingproducts/{product}/edit
    • 這樣在 Controller 中就可以用 $product 變數來接收,語意更清晰。
// 發票管理(美髮預約系統)
Route::resource('invoices', 'InvoiceController')->except(['show']);
  • 針對發票(收據)的 CRUD 路由。
// 使用者管理(美髮預約系統)
Route::resource('hairdressingusers', 'HairdressingUserController')->except(['show']);
  • 針對美髮系統使用者的 CRUD 路由。
// 預約服務明細(美髮預約系統)
Route::resource('appointmentservices', 'AppointmentServiceController')->except(['show']);
  • 針對「預約中包含了哪些服務」這個關聯資料表的 CRUD 路由。
// 收據明細(美髮預約系統)
Route::resource('invoiceitems', 'InvoiceItemController')->except(['show']);
  • 針對「發票中包含了哪些商品/服務」這個明細資料的 CRUD 路由。
// 庫存異動紀錄(美髮預約系統)
Route::resource('inventorylogs', 'InventoryLogController')->except(['show']);
  • 針對商品庫存異動紀錄的 CRUD 路由。
// 設計師排班(美髮預約系統)
Route::resource('staffschedules', 'StaffScheduleController')->except(['show']);
  • 針對設計師排班時間表的 CRUD 路由。
// 美髮系統總覽首頁
Route::get('/hairdressing', 'HairdressingDashboardController@index')->name('hairdressing.dashboard');
  • 定義一個 GET 路由,訪問 /hairdressing 時,由 HairdressingDashboardControllerindex 方法處理。
  • name('hairdressing.dashboard') 給這個路由一個名稱,之後在程式碼中可以用 route('hairdressing.dashboard') 來產生 URL,不用硬編寫路徑。

SPA 美容系統(Spa System)

Route::middleware('auth.spa')->prefix('spa')->group(function () {
  • middleware('auth.spa'):這整個區塊的路由都需要通過 spa 認證守衛(guard)的驗證,也就是使用者必須先登入 SPA 系統才能訪問。
  • prefix('spa'):所有路由的 URL 前面都會加上 /spa 前綴。
  • group(function () { ... }):把多條路由包在一起,共用 middleware 和 prefix。
    Route::get('/menu', function () {
        return view('spa.menu', [
            'user' => \Illuminate\Support\Facades\Auth::guard('spa')->user(),
        ]);
    })->name('spa.menu');
  • 訪問 /spa/menu 時,直接回傳 spa.menu 這個 view。
  • 同時把當前登入的使用者資料(透過 Auth::guard('spa')->user() 取得)傳入 view 中,讓頁面可以顯示使用者資訊。
    Route::get('/dashboard', [SpaDashboardController::class, 'index'])->name('spa.dashboard');
  • 訪問 /spa/dashboard 時,由 SpaDashboardControllerindex 方法處理,通常是 SPA 系統的後台總覽頁面。
    Route::get('/appointments', [SpaAppointmentController::class, 'index'])->name('spa.appointments.index');
  • 訪問 /spa/appointments 時,顯示預約列表頁面。
    Route::middleware('spa.role:admin,receptionist')->group(function () {
  • 這一層 middleware 進一步限制:只有角色為 adminreceptionist 的使用者才能訪問區塊內的路由。
  • spa.role:admin,receptionist 是自定義的 middleware,用來檢查使用者的角色權限。
        Route::get('/appointments/create', [SpaAppointmentController::class, 'create'])->name('spa.appointments.create');
        Route::post('/appointments', [SpaAppointmentController::class, 'store'])->name('spa.appointments.store');
        Route::get('/appointments/{appointment}/edit', [SpaAppointmentController::class, 'edit'])->name('spa.appointments.edit');
        Route::put('/appointments/{appointment}', [SpaAppointmentController::class, 'update'])->name('spa.appointments.update');
        Route::delete('/appointments/{appointment}', [SpaAppointmentController::class, 'destroy'])->name('spa.appointments.destroy');
  • 這五條是手動定義的預約 CRUD 路由(新增、儲存、編輯、更新、刪除)。
  • 因為前面已經用 Route::resource 的例外方式處理過,這裡可能是為了更精細的權限控制或自訂流程而手動寫出。
     Route::resource('customers', 'Spa\CustomerController')->names('spa.customers');
     Route::resource('invoices', 'Spa\InvoiceController')->names('spa.invoices');
  • 針對 SPA 系統的顧客和發票,建立完整的 RESTful 路由。
  • names('spa.customers') 會為所有產生的路由名稱加上 spa.customers. 前綴,例如 spa.customers.index, spa.customers.create 等。
       Route::middleware('spa.role:admin')->group(function () {
  • 再往內一層,只有 admin 角色的使用者才能訪問的區塊(更高權限的功能)。
        Route::resource('inventory-logs', SpaInventoryLogController::class);
        
         Route::resource('products', '\App\Http\Controllers\Spa\SpaProductController')->names('spa.products');
         
         Route::resource('users', 'Spa\SpaUserController')->names('spa.users');
         
         Route::resource('services', 'Spa\ServiceController')->names('spa.services');
         
         Route::resource('staff', 'Spa\StaffController')->names('spa.staff');
             Route::resource('staff-schedules', 'Spa\StaffScheduleController')->names('spa.staff-schedules');
  • 這些是只有管理員才能操作的功能:庫存異動、產品管理、使用者管理、服務管理、設計師管理、排班管理。
  • 每個 Route::resource 都會自動產生 7 條路由(index, create, store, show, edit, update, destroy)。
    }); // 結束 spa.role:admin 區塊
    }); // 結束 spa.role:admin,receptionist 區塊

    Route::get('/appointments/{appointment}', [SpaAppointmentController::class, 'show'])->name('spa.appointments.show');
  • 這一行在 auth.spa 區塊內,但在角色限制區塊外,表示「所有已登入的 SPA 使用者」都可以查看單一預約詳情。
     Route::middleware('spa.role:admin')->group(function () {
         Route::resource('inventory-logs', 'Spa\InventoryLogController')->names('spa.inventory-logs');
   
        Route::resource('inventory-logs', 'Spa\InventoryLogController');
                
    });
  • 這裡有重複定義 inventory-logs 路由(可能是程式碼整理時的遺留),實際上第二條會被忽略或造成衝突,建議清理。

SPA 登入/登出與介紹頁(不需登入即可訪問)

// 補回:美容系統登入/登出路由(不需要 auth.spa middleware,因為登入前用不到)
Route::get('/spa-login', [SpaAuthController::class, 'showLoginForm'])->name('spa.login');
Route::post('/spa-login', [SpaAuthController::class, 'login'])->name('spa.login.submit');
Route::post('/spa-logout', [SpaAuthController::class, 'logout'])->name('spa.logout');
  • 這三條路由沒有加 auth.spa middleware,因為使用者在登入前還不是認證使用者。
  • GET /spa-login:顯示登入表單。
  • POST /spa-login:提交登入表單,進行認證。
  • POST /spa-logout:登出。
Route::get('/spa-intro', function () {
    return view('spa.intro');
})->name('spa.intro');
  • SPA 系統的介紹頁面,任何訪客都可以訪問。

重點整理

路由前綴 用途 權限要求
/appointments, /customers, /staff 美髮預約系統 CRUD 無(需自行在 Controller 或 middleware 檢查)
/hairdressing 美髮系統總覽
/spa/* SPA 美容系統後台 auth.spa 登入
/spa/* 內的 admin,receptionist 區塊 預約、顧客、發票管理 adminreceptionist 角色
/spa/* 內的 admin 區塊 產品、使用者、排班等管理 admin 角色
/spa-login, /spa-logout, /spa-intro SPA 登入/登出/介紹 無(公開)

然後就來 customers 起手式:
從customers資料表開始~
然後是MVC的部分~

customers資料表

-- phpMyAdmin SQL Dump
-- version 5.2.3
-- https://www.phpmyadmin.net/
--
-- 主機: localhost:3306
-- 產生時間: 2026 年 09 月 08 日 12:23
-- 伺服器版本: 5.7.44
-- PHP 版本: 8.1.34

SET SQL_MODE = "NO_AUTO_VALUE_ON_ZERO";
START TRANSACTION;
SET time_zone = "+00:00";


/*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */;
/*!40101 SET @OLD_CHARACTER_SET_RESULTS=@@CHARACTER_SET_RESULTS */;
/*!40101 SET @OLD_COLLATION_CONNECTION=@@COLLATION_CONNECTION */;
/*!40101 SET NAMES utf8mb4 */;

--
-- 資料庫: `laihao_Hairdressing`
--

-- --------------------------------------------------------

--
-- 資料表結構 `customers`
--

CREATE TABLE `customers` (
  `id` bigint(20) UNSIGNED NOT NULL,
  `name` varchar(100) COLLATE utf8mb4_unicode_ci NOT NULL,
  `phone` varchar(20) COLLATE utf8mb4_unicode_ci NOT NULL,
  `email` varchar(150) COLLATE utf8mb4_unicode_ci DEFAULT NULL,
  `gender` enum('male','female','other') COLLATE utf8mb4_unicode_ci DEFAULT NULL,
  `birthday` date DEFAULT NULL,
  `notes` text COLLATE utf8mb4_unicode_ci,
  `allergy_notes` text COLLATE utf8mb4_unicode_ci,
  `hair_notes` text COLLATE utf8mb4_unicode_ci,
  `is_member` tinyint(1) NOT NULL DEFAULT '0',
  `member_no` varchar(20) COLLATE utf8mb4_unicode_ci DEFAULT NULL,
  `created_at` timestamp NULL DEFAULT CURRENT_TIMESTAMP,
  `updated_at` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;

--
-- 傾印資料表的資料 `customers`
--

INSERT INTO `customers` (`id`, `name`, `phone`, `email`, `gender`, `birthday`, `notes`, `allergy_notes`, `hair_notes`, `is_member`, `member_no`, `created_at`, `updated_at`) VALUES
(1, '王小婷', '0912345678', 'ting.wang@gmail.com', 'female', '1995-03-12', '偏好安靜服務', '對部分染膏氣味較敏感', '髮量多、自然捲、曾漂髮', 1, 'M20260001', '2026-08-22 03:00:52', '2026-08-22 03:00:52'),
(2, '陳雅雯', '0922111222', 'yawin.chen@gmail.com', 'female', '1990-07-25', '常做護髮', NULL, '髮質細軟、易扁塌', 1, 'M20260002', '2026-08-22 03:00:52', '2026-08-22 03:00:52'),
(3, '林先生', '0933555666', 'lin.man@gmail.com', 'male', '1988-11-02', '固定每月修剪', NULL, '短髮、兩側推高', 0, NULL, '2026-08-22 03:00:52', '2026-08-22 03:00:52'),
(4, '張可晴', '0977888999', 'keqing.zhang@gmail.com', 'female', '2000-09-18', '喜歡韓系髮型', '頭皮較敏感', '中長髮、曾染深棕色', 1, 'M20260003', '2026-08-22 03:00:52', '2026-08-22 03:00:52'),
(5, '黃TZU', '0612345678', 'huang123@gmail.com', 'female', '2002-02-07', NULL, NULL, NULL, 0, NULL, '2026-08-24 14:41:57', '2026-09-07 22:10:05');

--
-- 已傾印資料表的索引
--

--
-- 資料表索引 `customers`
--
ALTER TABLE `customers`
  ADD PRIMARY KEY (`id`),
  ADD UNIQUE KEY `customers_member_no_unique` (`member_no`),
  ADD KEY `customers_phone_index` (`phone`);

--
-- 在傾印的資料表使用自動遞增(AUTO_INCREMENT)
--

--
-- 使用資料表自動遞增(AUTO_INCREMENT) `customers`
--
ALTER TABLE `customers`
  MODIFY `id` bigint(20) UNSIGNED NOT NULL AUTO_INCREMENT, AUTO_INCREMENT=6;
COMMIT;

/*!40101 SET CHARACTER_SET_CLIENT=@OLD_CHARACTER_SET_CLIENT */;
/*!40101 SET CHARACTER_SET_RESULTS=@OLD_CHARACTER_SET_RESULTS */;
/*!40101 SET COLLATION_CONNECTION=@OLD_COLLATION_CONNECTION */;


上一篇
美髮預約系統_users的程式碼-新增/編輯資料內容的畫面
下一篇
美髮預約系統_customers的MVC內容
系列文
Laravel 讀碼源30
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言